import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.lang.*;
import java.io.*;

public class des_test {
    public byte[] iv,key,input;
    public Cipher enc;
    public Cipher dec;
    public File inputFile;
    public File outputFile;
    public FileInputStream in;
    public FileOutputStream out;
    public int pad;
    public int blocksize;

  public des_test(String mode,String args_iv, String args_key){
      try{
      
          iv = args_iv.getBytes("UTF8");
          key = args_key.getBytes("UTF8");

          cbcmode_start(mode);
      }catch(Exception e){System.out.println("Error encoding iv, key");}
      
  }

  public void cbcmode_start(String mode){
      if (mode.equals("enc")) {
          System.out.println("Starting Encryption...");
          try{

              System.out.println("opening files....");
              /******* OPEN FILES *********/
              inputFile = new File("cipher-outOFB");
              outputFile = new File("plain-outOFB");
              in = new FileInputStream(inputFile);
              out = new FileOutputStream(outputFile);


              System.out.println("adding pad....");
              /****** PADDING *******/
              blocksize = 1;
              if(in.available() % blocksize != 0){
              
                  if (in.available() < blocksize) {
                      input = new byte[blocksize];
                  }
                  else{   
                      int temp = (in.available()) / blocksize;
                      //System.out.println(temp);
                      temp++;
                      pad = (temp*8) - in.available();
                      input = new byte[in.available()+pad];
                  }
    
                  for (int i = in.available()-1;i<input.length;i++) {
                      input[i] = 0;
                  }
              }else{
                  input = new byte[in.available()];
              }
              in.read(input);
              System.out.println("# of bytes pad: " + input.length + " " + pad);


              System.out.println("Setting up Cipher....");
              /****** Cipher *******/
              enc = Cipher.getInstance("DES/OFB16/NOPadding");

              DESKeySpec dkey = new DESKeySpec(key);
              SecretKeyFactory fact = SecretKeyFactory.getInstance("DES");
              SecretKey deskey = fact.generateSecret(dkey);

              IvParameterSpec newIV = new IvParameterSpec(iv);
              enc.init(Cipher.ENCRYPT_MODE,deskey,newIV);
              //enc.init(Cipher.ENCRYPT_MODE,deskey);

              byte[] c = enc.doFinal(input);
              out.write(c);

              out.close();
              in.close();


          }catch(Exception e){System.out.println("Error starting enc mode: " + e.toString());}
          

      }
      else{
          System.out.println("Starting Decryption...");
          try{

              System.out.println("opening files....");
              /******* OPEN FILES *********/
              inputFile = new File("cipher-out_test");
              outputFile = new File("plain-in_test");
              in = new FileInputStream(inputFile);
              out = new FileOutputStream(outputFile);

              input = new byte[in.available()];

              in.read(input);


              System.out.println("Setting up Cipher....");
              /****** Cipher *******/
              dec = Cipher.getInstance("DES/OFB16/NOPadding");

              DESKeySpec dkey = new DESKeySpec(key);
              SecretKeyFactory fact = SecretKeyFactory.getInstance("DES");
              SecretKey deskey = fact.generateSecret(dkey);

              IvParameterSpec newIV = new IvParameterSpec(iv);
              dec.init(Cipher.DECRYPT_MODE,deskey,newIV);


              byte[] c = dec.doFinal(input);

              out.write(c);

          }catch(Exception e){System.out.println("Error starting dec mode: " + e.toString() + e.getStackTrace());}
      }
  }




  public byte[] encrypt(SecretKey key){
      return null;
  }

  public byte[] decrypt(SecretKey key){
      return null;
  }



  public static void main (String args[]) {

    //Check number of arguments for CBC mode
    if (args.length != 3 || args[1].length() != 8 || args[2].length() != 8) {
      System.out.println("Invalid arguments");
      System.out.println("Usage: java DESCBC [enc/dec] <initialization vector> <secret key>");
    }
    else{

      // If encryption
      if(args[0].equals("enc")){
        des_test DES1 = new des_test(args[0],args[1],args[2]);
        System.out.println("out");
      }

      // If decryption
      else if(args[0].equals("dec")){
        des_test DES2 = new des_test(args[0],args[1],args[2]);
      }
      else{
        System.out.println("Mode must be: 'enc' or 'dec'");
      }
      }


  }

}
